<?php
/**
 * Created by PhpStorm.
 * User: holobo
 * Date: 2019-03-09
 * Time: 17:28
 */

namespace apps\marriage\core\logic;

use think\Exception;
use think\facade\Log;
use vm\org\HttpUtil;

class WxMpLogic
{
    protected $token = '';
    protected $EncodingAESKey = '';
    protected $appid = '';
    protected $appSecret = '';

    protected $accessTokenCachePrefix = 'mp_access_token';
    protected $jsapiTicketCachePrefix = 'mp_jsapi_ticket';

    private $httpUtil = null;

    public function __construct()
    {
        $siteConfigService = service('SiteConfig', SERVICE_NAMESPACE);
        $this->token = $siteConfigService->getValueByCode('weixin_mp_app_token');
        $this->EncodingAESKey = $siteConfigService->getValueByCode('weixin_mp_encode_aeskey');
        $this->appid = $siteConfigService->getValueByCode('weixin_mp_app_id');
        $this->appSecret = $siteConfigService->getValueByCode('weixin_mp_app_secret');

        $this->httpUtil =  new HttpUtil();
    }

    public function getAppid()
    {
        return $this->appid;
    }

    protected function get($url)
    {
        $result = $this->httpUtil->curl($url, HttpUtil::REQUEST_METHOD_GET);
        $ret = json_decode($result, TRUE);
        if (isset($ret['errmsg']) && $ret['errcode'] != 0) {
            Log::error('请求微信接口出错，errcode:' . $ret['errcode'] . ',errmsg:' . $ret['errmsg']);
            throw new Exception($ret['errmsg']);
        }
        return $ret;
    }

    protected function post($url, $data)
    {
        $result = $this->httpUtil->curl($url, HttpUtil::REQUEST_METHOD_POST, $data);
        $ret = json_decode($result, TRUE);
        if (isset($ret['errmsg']) && $ret['errcode'] != 0) {
            Log::error('请求微信接口出错，errcode:' . $ret['errcode'] . ',errmsg:' . $ret['errmsg']);
            throw new Exception($ret['errmsg']);
        }
        return $ret;
    }

    /**
     * 用SHA1算法生成安全签名
     * @param $timestamp
     * @param $nonce
     * @param $encryptMsg
     * @return array
     */
    public function getSHA1($timestamp, $nonce, $encryptMsg)
    {
        $array = array($encryptMsg, $this->token, $timestamp, $nonce);
        sort($array, SORT_STRING);
        $str = implode($array);
        return sha1($str);
    }

    public function getAccessToken()
    {
        $data = cache($this->accessTokenCachePrefix);
        if ($data && $data['expire'] > time()) {
            return $data['access_token'];
        }
        $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=' . $this->appid . '&secret=' . $this->appSecret;
        $ret = $this->get($url);
        $accessToken = $ret['access_token'];
        $expiresIn = $ret['expires_in'];
        $expire = time() + $expiresIn - 60;
        cache($this->accessTokenCachePrefix, ['access_token' => $accessToken, 'expire' => $expire], $expire);
        return $accessToken;
    }

    public function getJsapiTicket()
    {
        $data = cache($this->jsapiTicketCachePrefix);
        if ($data && $data['expire'] > time()) {
            return $data['ticket'];
        }
        $url = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token='.$this->getAccessToken().'&type=jsapi';
        $ret = $this->get($url);
        $ticket = $ret['ticket'];
        $expiresIn = $ret['expires_in'];
        $expire = time() + $expiresIn - 60;
        cache($this->jsapiTicketCachePrefix, ['ticket' => $ticket, 'expire' => $expire], $expire);
        return $ticket;
    }

    public function genJsApiConfig($url)
    {
        $noncestr = rand_string(15);
        $timestamp = time();
        $jsapiTicket = $this->getJsapiTicket();
        $array = [
            'noncestr' => $noncestr,
            'timestamp' => $timestamp,
            'jsapi_ticket' => $jsapiTicket,
            'url' => $url
        ];
        ksort($array, SORT_STRING);
        $string1 = '';
        foreach ($array as $key => $val) {
            $string1 .= $string1 ? '&' : '';
            $string1 .= $key . '=' . $val;
        }
        $signature = sha1($string1);
        return [
            'appId' => $this->appid,
            'nonceStr' => $noncestr,
            'timestamp' => $timestamp,
            'signature' => $signature,
            'url' => $url
        ];
    }

    /**
     * 获取用户授权url
     * @param $rUrl
     * @param string $state
     * @return string
     */
    public function getUserAuthUrl($rUrl, $state = '', $scope = 'snsapi_userinfo')
    {
        $url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid='.$this->appid.'&redirect_uri='.urlencode($rUrl).'&response_type=code&scope='.$scope.'&state='.$state.'#wechat_redirect';
        return $url;
    }

    /**
     * 获取用户授权access_token
     * @param string $code 授权回调时传过来的code
     * @throws
     * @return array
     */
    public function getUserAuthAccessTokenByAuthorizationCode($code)
    {
        $url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$this->appid.'&secret='.$this->appSecret.'&code='.$code.'&grant_type=authorization_code';
        $ret = $this->get($url);
        return $ret;
    }

    /**
     * 刷新用户授权access_token
     * @param $refreshToken
     * @return mixed
     * @throws Exception
     */
    public function refreshUserAuthAccessToken($refreshToken)
    {
        $url = 'https://api.weixin.qq.com/sns/oauth2/refresh_token?appid='.$this->appid.'&grant_type=refresh_token&refresh_token=' . $refreshToken;
        $ret = $this->get($url);
        return $ret;
    }

    /**
     * 使用用户授权access_token和openid获取用户信息
     * @param $openId
     * @param $accessToken
     * @return mixed
     * @throws Exception
     */
    public function getUserInfoByAuthAccessToken($openId, $accessToken)
    {
        $url = 'https://api.weixin.qq.com/sns/userinfo?access_token='.$accessToken.'&openid='.$openId.'&lang=zh_CN';
        $ret = $this->get($url);
        return $ret;
    }

    /**
     * 获取用户信息
     * @param $openId
     * @return mixed
     * @throws Exception
     */
    public function getUserInfoByOpenId($openId)
    {
        $url = 'https://api.weixin.qq.com/cgi-bin/user/info?access_token='.$this->getAccessToken().'&openid='.$openId.'&lang=zh_CN';
        $ret = $this->get($url);
        return $ret;
    }
}